#pragma once

#include <iostream>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include<cstring>
#include<fcntl.h>
#include<sys/stat.h>

const std::string path = "/home/ubuntu/dailycode/共享内存博客代码/code"; // 记得在你的路径底下添加一个code文件
int pid = 0x666;
const std::string fifo_path = "/tmp/shm_sync_fifo"; // 命名管道路径


class shareshm
{
private:
    void CreateShmHelper(int shmflg)
    {
        _key = ::ftok(path.c_str(), pid);
        if (_key < 0)
        {
            std::cout << "ftok error" << std::endl;
        }

        _shmid = ::shmget(_key, 4096, shmflg);
        if (_shmid < 0)
        {
            std::cout << "shmget error" << std::endl;
        }
        std::cout << "shmid: " << _shmid << std::endl;
    }
    void CreateFifo() 
    {
        if (mkfifo(fifo_path.c_str(), 0666)) 
        {
            if (errno != EEXIST) 
            {
                perror("mkfifo error");
                exit(EXIT_FAILURE);
            }
        }
    }

public:
    shareshm() : _shmid(-1), _key(0), _addr(nullptr)
    {
    }
    void CreateShm() // 创建共享内存
    {
        CreateShmHelper(IPC_CREAT | IPC_EXCL | 0666);
    }
    void GetShm() // 获取共享内存
    {
        CreateShmHelper(IPC_CREAT);
    }
    void AttachShm() // 挂载到虚拟地址
    {
        _addr = shmat(_shmid, nullptr, 0); // 这里默认让系统分配虚拟地址
        if ((long long)_addr == -1)        // 因为我们这里是64位的系统，void*指针大小为8，如果是32位，就可以使用int
        {
            std::cout << "attach error" << std::endl;
        }
    }
    void DetachShm() // 取消物理地址与虚拟地址的映射关系
    {
        if (_addr != nullptr)
            ::shmdt(_addr);
        std::cout << "detach done: " << std::endl;
    }
    void DeleteShm() // 删除共享内存
    {
        shmctl(_shmid, IPC_RMID, nullptr);
    }
    void *GetAddr()
    {
        return _addr;
    }

    // 新增命名管道方法
    void WaitForSignal() 
    {
        int fd = open(fifo_path.c_str(), O_RDONLY);
        char buf[1];
        read(fd, buf, 1); // 阻塞等待信号
        close(fd);
    }

    void SendSignal() 
    {
        int fd = open(fifo_path.c_str(), O_WRONLY);
        char buf[1] = {'1'};
        write(fd, buf, 1); // 发送信号
        close(fd);
    }

private:
    int _shmid;
    key_t _key;
    void *_addr;
};

shareshm shm;